/* Copyright 2011 Tobias Marschall, Email: tm@cwi.nl 
 * 
 * This file is part of string-cover.
 *
 * string-cover is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * string-cover is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with string-cover.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <vector>

#include "Solution.h"

using namespace std;

Solution::Solution(const ProblemInstance& instance, double score, std::auto_ptr<std::vector<StringFactorization> > factorizations) : instance(instance), factorizations(factorizations), solution_substrings(instance.getSubstrings().size()), score(score) {
	computSolutionSubset();
}

Solution::Solution(const ProblemInstance& instance, std::auto_ptr<std::vector<StringFactorization> > factorizations) : instance(instance), factorizations(factorizations), solution_substrings(instance.getSubstrings().size()) {
	computSolutionSubset();
	score = 0.0;
	size_t n = solution_substrings.find_first();
	for (; n!=boost::dynamic_bitset<>::npos; n=solution_substrings.find_next(n)) {
		score += instance.getWeight(n);
	}
}

Solution::Solution(const Solution& solution) : instance(solution.instance), factorizations(new vector<StringFactorization>(*solution.factorizations)), solution_substrings(solution.solution_substrings), score(score) {
}

Solution::~Solution() {
}

void Solution::computSolutionSubset() {
	const vector<string>& strings = instance.getStrings();
	const SubstringStore& substrings = instance.getSubstrings();
	for (size_t string_nr=0; string_nr<strings.size(); ++string_nr) {
		const boost::dynamic_bitset<>& breakpoints = this->factorizations->at(string_nr).getBreakpoints();
		size_t start = 0;
		size_t n = breakpoints.find_first();
		for (; n!=boost::dynamic_bitset<>::npos; n=breakpoints.find_next(n)) {
			solution_substrings.set(substrings.getIndex(string_nr,start,n+1));
			start = n+1;
		}
		solution_substrings.set(substrings.getIndex(string_nr,start,strings[string_nr].size()));
	}
}


double Solution::getScore() const {
	return score;
}

void Solution::printFactorizations(std::ostream & os) const {
	const vector<string>& strings = instance.getStrings();
	for (size_t i=0; i<strings.size(); ++i) {
		os << factorizations->at(i).printFactorizedString(strings[i]) << endl;
	}
}

auto_ptr<Solution> Solution::createAllStringsSolution(const ProblemInstance& instance) {
	const vector<string>& strings = instance.getStrings();
	auto_ptr<vector<StringFactorization> > factorizations(new vector<StringFactorization>());
	for (size_t string_nr=0; string_nr<strings.size(); ++string_nr) {
		factorizations->push_back(StringFactorization(strings[string_nr].size()));
	}
	auto_ptr<Solution> solution(new Solution(instance, 0.0, factorizations));
	const boost::dynamic_bitset<>& solution_substrings = solution->getSubstrings();
	size_t n = solution_substrings.find_first();
	double score = 0.0;
	for (; n!=boost::dynamic_bitset<>::npos; n=solution_substrings.find_next(n)) {
		score += instance.getWeight(n);
	}
	solution->score = score;
	return solution;
}

auto_ptr<Solution> Solution::createAllLettersSolution(const ProblemInstance& instance) {
	const vector<string>& strings = instance.getStrings();
	auto_ptr<vector<StringFactorization> > factorizations(new vector<StringFactorization>());
	for (size_t string_nr=0; string_nr<strings.size(); ++string_nr) {
		factorizations->push_back(StringFactorization(strings[string_nr].size()));
		factorizations->at(string_nr).addAllBreakpoints();
	}
	auto_ptr<Solution> solution(new Solution(instance, 0.0, factorizations));
	const boost::dynamic_bitset<>& solution_substrings = solution->getSubstrings();
	size_t n = solution_substrings.find_first();
	double score = 0.0;
	for (; n!=boost::dynamic_bitset<>::npos; n=solution_substrings.find_next(n)) {
		score += instance.getWeight(n);
	}
	solution->score = score;
	return solution;
}

const boost::dynamic_bitset<> & Solution::getSubstrings() const {
	return solution_substrings;
}

std::ostream& operator<<(std::ostream & os, const Solution& solution) {
	const SubstringStore& substrings = solution.instance.getSubstrings();
	os << "{";
	size_t i = 0;
	size_t n = solution.solution_substrings.find_first();
	for (; n!=boost::dynamic_bitset<>::npos; n=solution.solution_substrings.find_next(n)) {
		if (i++>0) os << ',';
		os << substrings.getSubstring(n);
	}
	os << "}";
	return os;
}
